﻿using Microsoft.Extensions.Options;
using Orleans.EventSourcing;
using Orleans.Providers;

namespace orleans_demo.Services
{
    [StorageProvider(ProviderName = "SnapshotStore")]
   // [LogConsistencyProvider(ProviderName = "LogStorage")]
    public class AccountGrain : JournaledGrain<AccountState, AccountEvent>, IAccountGrain
    {
        // 快照频率：每10个事件保存一次快照
#if ORLEANS_7
    protected override int SnapshotFrequency => 10;
#else
        //protected override void ConfigureEventSourcing(ISnapshotConfiguration config)
        //{
        //    config.UseSnapshot(every: 10);
        //    config.UseCompression();      // 可选：启用快照压缩
        //}
#endif

        public async Task Deposit(decimal amount)
        {
            if (amount <= 0)
                throw new ArgumentException("Deposit amount must be positive");
            // 1. 触发存款事件
            RaiseEvent(new DepositedEvent(amount, DateTime.UtcNow));
            // 2. 持久化事件到事件存储
            await ConfirmEvents();
        }

        public async Task Withdraw(decimal amount)
        {
            if (amount <= 0)
                throw new ArgumentException("Withdrawal amount must be positive");

            if (State.Balance < amount)
                throw new InvalidOperationException("Insufficient funds");

            RaiseEvent(new WithdrawnEvent(amount, DateTime.UtcNow));
            await ConfirmEvents();
        }

        public Task<decimal> GetBalance() => Task.FromResult(State.Balance);

        public Task<string> GetHistory()
        {
            var history = $"Account {this.GetPrimaryKey()} history:\n";
            history += $"Current balance: {State.Balance}\n";
            history += $"Last transaction: {State.LastTransactionDate}\n";
            return Task.FromResult(history);
        }

        // 应用事件到状态
        protected override void OnStateChanged()
        {
            // 可以在这里添加状态变更后的逻辑
            Console.WriteLine($"Account {this.GetPrimaryKey()} state updated. New balance: {State.Balance}");
        }

        protected override void TransitionState(AccountState state, AccountEvent @event)
        {
            switch (@event)
            {
                case DepositedEvent deposited:
                    state.Balance += deposited.Amount;
                    state.LastTransactionDate = deposited.Timestamp;
                    break;

                case WithdrawnEvent withdrawn:
                    state.Balance -= withdrawn.Amount;
                    state.LastTransactionDate = withdrawn.Timestamp;
                    break;
            }
        }
    }

    // 状态类
    public class AccountState
    {
        public decimal Balance { get; set; }
        public DateTime LastTransactionDate { get; set; }
    }

    // 事件基类
    public abstract class AccountEvent
    {
        public DateTime Timestamp { get; set; }
    }

    // 存款事件
    public class DepositedEvent : AccountEvent
    {
        public decimal Amount { get; }

        public DepositedEvent(decimal amount, DateTime timestamp)
        {
            Amount = amount;
            Timestamp = timestamp;
        }
    }

    // 取款事件
    public class WithdrawnEvent : AccountEvent
    {
        public decimal Amount { get; }

        public WithdrawnEvent(decimal amount, DateTime timestamp)
        {
            Amount = amount;
            Timestamp = timestamp;
        }
    }
}
